import {
  Controller,
  Get,
  Req,
  UnauthorizedException,
  Inject,
  BadRequestException,
  Query,
} from '@nestjs/common';
import { Cache } from 'cache-manager';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { ConfigService } from '@nestjs/config';
import { UserService } from './user/user.service';
import { getRedisKey, safeOutput } from './utils';
import { SkipLogin } from './common/decorator/public.decorator';
import { AuthService } from './auth/auth.service';
import { IsNull } from 'typeorm';

@Controller()
export class AppController {
  constructor(
    @Inject(CACHE_MANAGER) private cacheManager: Cache,
    private userService: UserService,
    private authService: AuthService,
    private configService: ConfigService,
  ) {}

  /**
   * 返回登录用户的基本信息
   *
   * @param {*} request
   * @return {*}
   * @memberof AppController
   */
  @SkipLogin()
  @Get('/validate')
  async validate(@Req() request: any): Promise<any> {
    // 获取token
    const bearerHeader = request.headers.authorization;
    if ( typeof bearerHeader === 'string' && bearerHeader.startsWith('Bearer ') ) {
      const token: string = bearerHeader.substring(7, bearerHeader.length);
      const payload: any = await this.authService.verifyToken(token);

      if (!payload) throw new UnauthorizedException(`请重新登陆`);

      // token有效，获取用户信息，先从Redis里取，取不到再从库里取
      const { userId } = payload || {};
      const userInfoRedisKey = getRedisKey(userId, 'user', 'info');
      let userInfo: any = await this.cacheManager.store.get(userInfoRedisKey);
      if (!userInfo) {
        userInfo = await this.userService.findUser({ id: userId, deleted_at: IsNull() }); // 用户基本信息
        if (!userInfo) throw new UnauthorizedException(`请先注册后登陆`);

        // 数据脱敏
        userInfo = safeOutput(userInfo);

        // 用户信息缓存进Redis
        await this.cacheManager.store.set( userInfoRedisKey, userInfo, this.configService.get('REDIS_USER_EXPIRE') ); // 0是永不过期
      }

      return userInfo;
    }

    throw new UnauthorizedException(`请重新登陆`);
  }

  /**
   * 刷新token
   *
   * @param {*} query
   * @return {*}
   * @memberof AppController
   */
  @SkipLogin()
  @Get('/refresh_token')
  async updateToken(@Query() query: any): Promise<any> {
    const { token = '' } = query || {};
    if (!token) throw new UnauthorizedException(`请重新登陆`);

    const { userId } = (await this.authService.verifyToken(token)) || {};
    if (!userId) throw new UnauthorizedException(`请重新登陆`);

    const userInfoRedisKey = getRedisKey(userId, 'user', 'info');
    const userInfo = await this.cacheManager.store.get(userInfoRedisKey);
    if (!userInfo) throw new UnauthorizedException(`请重新登陆`);

    // 查询数据库中用户是否存在
    const user = await this.userService.checkExist({
      id: userId,
      deleted_at: IsNull(),
    });
    if (!user) throw new UnauthorizedException(`请重新登陆`);

    return await this.authService.getToken(userId);
  }
}
